using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Windows.Forms;
using System.IO.Ports;

namespace LogAnalyzer.Grabbers
{
    public class SerialPortGrabber : GrabberBase
    {
        SerialPort _port = null;
        SerialDataReceivedEventHandler _hnd = null;
        object _lockReadSerial = new object();


        public SerialPortGrabber()
        {
            _hnd = new SerialDataReceivedEventHandler(_port_DataReceived);
        }


        private string PortName
        {
            get
            {
                string name = "";
                if (Config.ContainsKey("serialPortGrabber.portName"))
                    name = Config["serialPortGrabber.portName"];
                return name;
            }
            set
            {
                if (Config.ContainsKey("serialPortGrabber.portName"))
                    Config.Remove("serialPortGrabber.portName");
                Config["serialPortGrabber.portName"] = value;
            }
        }
        private int PortBaudRate
        {
            get
            {
                int baud = 0;
                if (Config.ContainsKey("serialPortGrabber.portBaudRate"))
                    int.TryParse(Config["serialPortGrabber.portBaudRate"], out baud);
                return baud;
            }
            set
            {
                if (Config.ContainsKey("serialPortGrabber.portBaudRate"))
                    Config.Remove("serialPortGrabber.portBaudRate");
                Config["serialPortGrabber.portBaudRate"] = value.ToString();
            }
        }
        private Parity Parity
        {
            get
            {
                Parity parity = Parity.None;
                if (Config.ContainsKey("serialPortGrabber.portParity"))
                    try
                    {
                        parity = (Parity)Enum.Parse(typeof(Parity), Config["serialPortGrabber.portParity"]);
                    }
                    catch { }
                return parity;
            }
            set
            {
                if (Config.ContainsKey("serialPortGrabber.portParity"))
                    Config.Remove("serialPortGrabber.portParity");
                Config["serialPortGrabber.portParity"] = value.ToString();
            }
        }
        private StopBits StopBits
        {
            get
            {
                StopBits stopBits = StopBits.One;
                if (Config.ContainsKey("serialPortGrabber.portStopBits"))
                    try
                    {
                        stopBits = (StopBits)Enum.Parse(typeof(StopBits), Config["serialPortGrabber.portStopBits"]);
                    }
                    catch { }
                return stopBits;
            }
            set
            {
                if (Config.ContainsKey("serialPortGrabber.portStopBits"))
                    Config.Remove("serialPortGrabber.portStopBits");
                Config["serialPortGrabber.portStopBits"] = value.ToString();
            }
        }
        private bool DTREnabled
        {
            get
            {
                bool dtrEna = false;
                if (Config.ContainsKey("serialPortGrabber.portDtrEnabled"))
                    bool.TryParse(Config["serialPortGrabber.portDtrEnabled"], out dtrEna);
                return dtrEna;
            }
            set
            {
                if (Config.ContainsKey("serialPortGrabber.portDtrEnabled"))
                    Config.Remove("serialPortGrabber.portDtrEnabled");
                Config["serialPortGrabber.portDtrEnabled"] = value.ToString();
            }
        }
        private bool RTSEnabled
        {
            get
            {
                bool rtsEna = false;
                if (Config.ContainsKey("serialPortGrabber.portRtsEnabled"))
                    bool.TryParse(Config["serialPortGrabber.portRtsEnabled"], out rtsEna);
                return rtsEna;
            }
            set
            {
                if (Config.ContainsKey("serialPortGrabber.portRtsEnabled"))
                    Config.Remove("serialPortGrabber.portRtsEnabled");
                Config["serialPortGrabber.portRtsEnabled"] = value.ToString();
            }
        }
        private int DataBits
        {
            get
            {
                int bits = 8;
                if (Config.ContainsKey("serialPortGrabber.portDataBits"))
                    int.TryParse(Config["serialPortGrabber.portDataBits"], out bits);
                return bits;
            }
            set
            {
                if (Config.ContainsKey("serialPortGrabber.portDataBits"))
                    Config.Remove("serialPortGrabber.portDataBits");
                Config["serialPortGrabber.portDataBits"] = value.ToString();
            }
        }
        private DataEncoding Encoding
        {
            get
            {
                DataEncoding enc = DataEncoding.UTF8;
                if (Config.ContainsKey("serialPortGrabber.encoding"))
                    try
                    {
                        enc = (DataEncoding)Enum.Parse(typeof(DataEncoding), Config["serialPortGrabber.encoding"]);
                    }
                    catch { }
                return enc;
            }
            set
            {
                if (Config.ContainsKey("serialPortGrabber.encoding"))
                    Config.Remove("serialPortGrabber.encoding");
                Config["serialPortGrabber.encoding"] = value.ToString();
            }
        }


        public override DialogResult ShowConfigDialog()
        {
            using (Dialogs.SerialPortGrabberCfg cfg = new LogAnalyzer.Grabbers.Dialogs.SerialPortGrabberCfg())
            {
                cfg.PortName = PortName;
                cfg.PortBaudRate = PortBaudRate;
                cfg.StopBits = StopBits;
                cfg.Parity = Parity;
                cfg.DataBits = DataBits;
                cfg.DTREnabled = DTREnabled;
                cfg.RTSEnabled = RTSEnabled;
                cfg.Encoding = Encoding;


                DialogResult dlgRes = cfg.ShowDialog();


                if (dlgRes == DialogResult.OK)
                {
                    PortName = cfg.PortName;
                    PortBaudRate = cfg.PortBaudRate;
                    StopBits = cfg.StopBits;
                    Parity = cfg.Parity;
                    DataBits = cfg.DataBits;
                    DTREnabled = cfg.DTREnabled;
                    RTSEnabled = cfg.RTSEnabled;
                    Encoding = cfg.Encoding;
                }
                return dlgRes;
            }
        }

        protected override void StartGrab(bool isRestart)
        {
            DestroyPort();

            _port = new SerialPort(PortName, PortBaudRate);
            _port.DataReceived += _hnd;
            _port.Parity = Parity;
            _port.StopBits = StopBits;
            _port.DataBits = DataBits;
            _port.DtrEnable = DTREnabled;
            _port.RtsEnable = RTSEnabled;
            switch (Encoding)
            {
                case DataEncoding.ASCII:
                    _port.Encoding = System.Text.Encoding.ASCII;
                    break;
                case DataEncoding.BigEndianUnicode:
                    _port.Encoding = System.Text.Encoding.BigEndianUnicode;
                    break;
                case DataEncoding.Unicode:
                    _port.Encoding = System.Text.Encoding.Unicode;
                    break;
                case DataEncoding.UTF32:
                    _port.Encoding = System.Text.Encoding.UTF32;
                    break;
                case DataEncoding.UTF7: 
                    _port.Encoding = System.Text.Encoding.UTF7;
                    break;
                case DataEncoding.UTF8:
                    _port.Encoding = System.Text.Encoding.UTF8;
                    break;
                default:
                    _port.Encoding = System.Text.Encoding.Default;
                    break;
            }
            _port.Open();
        }

        public override void StopGrab()
        {
            DestroyPort();
        }

        public override string TextForViewer
        {
            get { return PortName + " @ " + PortBaudRate.ToString(); }
        }

        public override void Dispose()
        {
            DestroyPort();
        }
        

        private void DestroyPort()
        {
            if (_port != null)
            {
                if (_port.IsOpen)
                    _port.Close();

                _port.DataReceived -= _hnd;
                _port.Dispose();
                _port = null;
            }
        }
        
        void _port_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            lock (_lockReadSerial)
            {
                string s = "";
                try
                {
                    s = _port.ReadExisting();
                }
                catch { }

                HandleNewString(s);

            }
        }

    }
}
